// SDL2_15 [SDL StarField v0.1].nova // Original version by: Will Schenk (written in Java 1.1). // Updated & converted to Nova by: Robert Platt - 25/02/2026. using namespace lib.emscripten; using namespace lib.math; using namespace lib.sdl2; // The Star class to handle 3D projection and rendering. class Star { public int x, y, z; public int hPos, vPos; public Star( ) { reset( true ); } public void reset( bool randomZ ) { x = ( Math.rand( ) % 640 ) - 320; y = ( Math.rand( ) % 480 ) - 240; if ( x == 0 && y == 0 ) x = 10; z = randomZ ? ( Math.rand( ) % 100 ) : 100; } public void updateAndRender( SDL_Renderer r, int renderStyle ) { z -= 1; if ( z < -63 ) reset( false ); // 3D to 2D Projection. hPos = ( x * 64 ) / (64 + z ) + 320; vPos = ( y * 64 ) / (64 + z ) + 240; // Screen bounds check. if ( hPos < 0 || hPos > 640 || vPos < 0 || vPos > 480 ) { reset( false ); } // Depth shading. if ( z > 50 ) SDL2.SDL_SetRenderDrawColor( r, 128, 128, 128, 255 ); else if ( z > 25 ) SDL2.SDL_SetRenderDrawColor( r, 192, 192, 192, 255) ; else SDL2.SDL_SetRenderDrawColor( r, 255, 255, 255, 255 ); // Render shapes based on the current 'renderStyle'. if ( renderStyle == 0 ) { int size = ( 100 - z ) / 50; if ( size <= 0 ) size = 1; SDL_Rect rect = new SDL_Rect( hPos, vPos, size, size ); SDL2.SDL_RenderFillRect( r, rect ); } else { int size = ( 100 - z ) / 20; SDL2.SDL_RenderDrawLine( r, hPos - size, vPos, hPos + size, vPos ); SDL2.SDL_RenderDrawLine( r, hPos, vPos - size, hPos, vPos + size ); } } } // The main application class. class StarField { private static SDL_Window w; private static SDL_Renderer r; private static bool runFlag; private static Star[] stars; private static int starType; private static int WIDTH; private static int HEIGHT; private static int NUM_STARS; public static void main( String[] args ) { Stream.writeLine( "SDL2_15 [SDL StarField v0.1].nova" ); runFlag = true; starType = 0; WIDTH = 640; HEIGHT = 480; NUM_STARS = 250; Emscripten.disableControls( ); SDL2.SDL_Init( SDL2.SDL_INIT_VIDEO ); w = SDL2.SDL_CreateWindow( "SDL2_15 [SDL StarField v0.1]", SDL2.SDL_WINDOWPOS_CENTERED, SDL2.SDL_WINDOWPOS_CENTERED, WIDTH, HEIGHT, SDL2.SDL_WINDOW_SHOWN ); if ( w == null ) return; r = SDL2.SDL_CreateRenderer( w, -1, SDL2.SDL_RENDERER_ACCELERATED | SDL2.SDL_RENDERER_PRESENTVSYNC ); stars = new Star[ NUM_STARS ]; for ( int i = 0; i < NUM_STARS; i++ ) { stars[ i ] = new Star( ); } if ( Emscripten.isActive( ) ) { int simulate_infinite_loop = 1; // Call the function repeatedly. int fps = -1; // Call the function as fast as the browser wants to render (typically 60fps). Emscripten.setMainLoop( renderFrame, fps, simulate_infinite_loop ); } else { do { renderFrame( ); } while ( runFlag ); } SDL2.SDL_DestroyRenderer( r ); SDL2.SDL_DestroyWindow( w ); SDL2.SDL_Quit( ); } public static void renderFrame( ) { SDL_Event e = SDL2.SDL_PollEvent( ); if ( e != null ) { if ( e.id == SDL2.SDL_QUIT ) { runFlag = false; } else if ( e.id == SDL2.SDL_KEYDOWN ) { // Cast to a keyboard event. SDL_KeyboardEvent kbEvent = (SDL_KeyboardEvent)e; if ( kbEvent.sym == SDL2.SDLK_SPACE ) { starType = ( starType == 0 ) ? 1 : 0; } } } SDL2.SDL_SetRenderDrawColor( r, 0, 0, 77, 255 ); SDL2.SDL_RenderClear( r ); for ( int i = 0; i < NUM_STARS; i++ ) { stars[ i ].updateAndRender( r, starType ); } SDL2.SDL_RenderPresent( r ); } }